package github.ziwukun.jsonql.exe;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import github.ziwukun.jsonql.analysis.AnalysisException;
import github.ziwukun.jsonql.lang.JSONQL;
import github.ziwukun.jsonql.lang.Limit;
import github.ziwukun.jsonql.lang.SelectItem;
import github.ziwukun.jsonql.lang.Sort;
import github.ziwukun.jsonql.lang.Where;
import github.ziwukun.jsonql.orm.ContainerType;
import lombok.NonNull;

public class MySQLCtnQLExecutor implements CtnQLExecutor{
	private static Logger logger = LoggerFactory.getLogger(MySQLCtnQLExecutor.class);
	private DataSource datasource;
	MySQLCtnQLExecutor(@NonNull DataSource datasource){
		this.datasource = datasource;
	}
	
	@Override
	public ContainerType support() {
		return ContainerType.MYSQL;
	}

	@SuppressWarnings("rawtypes")
	@Override
	public List<Map> exe(JSONQL ql) {
		Connection connection = null;
		PreparedStatement ps = null;
		try {
			List<Object> params = new LinkedList<Object>();
			String sql = toSQL(ql, params);
			logger.debug(
				"\nJSON QL\t=====> " + ql.toJSONQL() + "\nSQL\t=====> " + sql + 
				"\nparams\t=====> " + params);
			
			connection =  datasource.getConnection();;
			ps = connection.prepareStatement(sql);
			for (int i = 0; i < params.size(); i++) {
				ps.setObject( + 1, params.get(i));
			}
			List<SelectItem> selectCols = ql.select().listItems();
			// 执行查询
			ResultSet resultSet = ps.executeQuery();
			List<Map> resultList = new LinkedList<>();
			
			while (resultSet.next()) {
				Map<String, Object> rsItem = new HashMap<>();
				for(SelectItem col : selectCols) {
					Object colVal = resultSet.getObject(col.prop());
					rsItem.put(col.prop(), colVal);
				}
				
				resultList.add(rsItem);
			}
			return resultList;
		}
		catch (AnalysisException e) {
			throw e;
		}
		catch (Exception e) {
			throw new RuntimeException("执行SQL失败",e);
		}
		finally {
			try {
				if(ps != null) {
					ps.close();
				}
				if(connection != null) {
					connection.close();
				}
			} catch (Exception e) {
				throw new RuntimeException("关闭流异常",e);
			}
		}
	}

	private String toSQL(JSONQL query,List<Object> params) {
		StringBuilder sql = new StringBuilder();
		sql.append("SELECT ").append(JQLToSqlMgr.selectToSql(query.select()));
		sql.append(" FROM ").append(query.from());
		
		Where where = query.where();
		if(where != null) {
			sql.append(" WHERE ").append(
				JQLToSqlMgr.whereToSql(where, params));
		}
		
		Sort sort = query.sort();
		if(sort != null) {
			sql.append(" ORDER BY ").append(
				JQLToSqlMgr.sortToSql(sort));
					
		}
		
		Limit limit = query.limit();
		if(limit != null) {
			sql.append(JQLToSqlMgr.limitToSql(limit));
		}
		
		return sql.toString();
	}
}
